package suncertify.gui.panels;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import suncertify.application.ApplicationMode;
import suncertify.application.Strings;

/**
 * Provides a JPanel to type the database file path in a text field or to browse for it using the {@link JFileChooser}.
 * The panel consists of the following components:
 * <ol>
 * <li>A {@link JLabel} with this text: {@link Strings#CAP_DATABASE_FILE_LABEL}</li>
 * <li>A {@link JTextField} to enter the database file path.</li>
 * <li>A {@link JButton} with text {@link Strings#CAP_BROWSE}. Clicking this button shows the {@link JFileChooser} which
 * allows the user to browse and select the database file path. The selected file's path is shown in the database text
 * field.</li>
 * </ol>
 * 
 * <p>
 * The three components are aligned to the left and appear in one row. This class is used in the
 * {@link ApplicationMode#SERVER} and {@link ApplicationMode#STANDALONE_CLIENT}. The database file path can be typed in
 * the text field or the database file can be selected in the file chooser.
 * 
 */
public class FileLocationPanel extends JPanel {

    /**
     * Automatically generated serialization version ID.
     */
    private static final long serialVersionUID = 1751664754281950728L;

    /**
     * Declaration of the path label.
     */
    private JLabel pathLabel;

    /**
     * Declares the path text field.
     */
    private JTextField pathTextField;

    /**
     * Declares the browse button.
     */
    private JButton browseButton;

    /**
     * Determines the current directory for the {@link JFileChooser}.
     */
    private String fileChooserCurrentDirectory;

    /**
     * Constructs the class with the specified parameters. The constructor creates the label, text field and browse
     * button and adds them to the panel. The three components are aligned from left to right in the panel. The
     * <code>databaseFilePath</code> parameter is put in the path text field as it is. The
     * <code>fileChooserCurrentDirectory</code> is assigned to a member variable and used later when the browse button
     * initializes the file chooser dialog.
     * 
     * <p>
     * The constructor does not validate the input parameters and depends on the caller to do the validation.
     * 
     * @param databasFilePath
     *            Usually this value is the path to the database file that is saved in the application's properties
     *            file. If the properties file is not created yet then the caller usually provides an assumed path using
     *            the current user directory. This value is put in the path text field as it is.
     * @param fileChooserCurrentDirectory
     *            Usually the starting path of the file chooser dialog.
     * 
     * @throws NullPointerException
     *             If any of the input parameters are null.
     */
    public FileLocationPanel(String databasFilePath, String fileChooserCurrentDirectory) {

	if (databasFilePath == null) {
	    throw new NullPointerException(
		    "FileLocationPanel cannot be constructed with null databaseFilePath parameter!");
	}

	if (fileChooserCurrentDirectory == null) {
	    throw new NullPointerException(
		    "FileLocationPanel cannot be constructed with null fileChooserCurrentDirectory parameter!");
	}

	this.fileChooserCurrentDirectory = fileChooserCurrentDirectory;

	this.pathLabel = new JLabel(Strings.CAP_DATABASE_FILE_LABEL);
	this.pathLabel.setDisplayedMnemonic(KeyEvent.VK_F);

	this.pathTextField = new JTextField(40);
	this.pathTextField.setText(databasFilePath);
	this.pathTextField.setToolTipText(Strings.TIP_DATABASE_FILE);
	this.pathLabel.setLabelFor(this.pathTextField);

	this.browseButton = new JButton(Strings.CAP_BROWSE);
	this.browseButton.addActionListener(new BrowseFileActionListener());
	this.browseButton.setToolTipText(Strings.TIP_BROWSE_BUTTON);
	this.browseButton.setMnemonic(KeyEvent.VK_W);

	this.setLayout(new FlowLayout(FlowLayout.LEFT));

	this.add(this.pathLabel);
	this.add(this.pathTextField);
	this.add(this.browseButton);
    }

    /**
     * Provides an implementation for the {@link ActionListener} interface. An instance of this class is assigned to the
     * browse button action's command. The {@link ActionListener#actionPerformed(ActionEvent)} function is called when
     * the browse button is clicked which shows the {@link JFileChooser}.
     * 
     */
    private class BrowseFileActionListener implements ActionListener {

	/**
	 * Called when the browse button is clicked. Creates one instance of the {@link JFileChooser} class using the
	 * <code>fileChooserCurrentDirectory</code> passed to the {@link FileLocationPanel} constructor. The file
	 * chooser is constructed to show only folders and files that have the applications database file extension,
	 * other file types are not shown in the file chooser dialog.
	 * 
	 * <p>
	 * When the function shows the {@link JFileChooser} it is blocked until a file that has the same extension as
	 * the application's database file is selected and the file chooser is submitted, in this case the function puts
	 * the selected file's path in the panel's text field.
	 * 
	 * @param ae
	 *            See {@link ActionEvent}. This parameter is not used in this function.
	 * 
	 */
	public void actionPerformed(ActionEvent ae) {

	    JFileChooser fileChooser = new JFileChooser(fileChooserCurrentDirectory);
	    fileChooser.addChoosableFileFilter(new javax.swing.filechooser.FileFilter() {

		public boolean accept(File f) {

		    if (f.isFile()) {
			return f.getName().endsWith(Strings.CAP_DATABASE_FILE_EXTENSION);
		    } else {
			return true;
		    }
		}

		public String getDescription() {
		    return Strings.DATABASE_FILE_CHOOSER_DESCRIPTION;
		}
	    });

	    // if the user selected a file, update the file name on screen
	    if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
		pathTextField.setText(fileChooser.getSelectedFile().toString());
	    }
	}
    }

    /**
     * Returns the content of the path {@link JTextField} which represents the database file path.
     * 
     * @return The database file path.
     */
    public String getDatabaseFilePath() {

	return this.pathTextField.getText().trim();
    }

    /**
     * Enables or disables the label, text field and browse button components.
     * 
     * @param enabled
     *            True to enable all panel components, false to disable all panel components.
     */
    public void setEnableState(boolean enabled) {
	this.pathLabel.setEnabled(enabled);
	this.pathTextField.setEnabled(enabled);
	this.browseButton.setEnabled(enabled);
    }
}
